package weaver.splittable;

import org.apache.log4j.Logger;
import weaver.conn.ConnectionPool;
import weaver.conn.WeaverConnection;
import weaver.conn.WeaverStatement;
import weaver.general.BaseBean;
import weaver.splittable.biz.STBizInitializer;
import weaver.splittable.biz.STBizInterceptor;
import weaver.splittable.db.STDBConstants;
import weaver.splittable.db.STDBSupport;
import weaver.splittable.db.STDBUtil;
import weaver.splittable.db.oracle.STOracleCreateTableUtil;
import weaver.splittable.task.STSyncTask;
import weaver.splittable.task.STThresholdTask;
import java.sql.SQLException;
import java.util.Timer;

/**
 * 初始化分表组件
 * author: YUEYANG 2023-01-12
 */
public class STInstaller {

    private static final Logger LOGGER = Logger.getLogger(STConfig.LOGGER_NAME);

    private static boolean isInstalled = false;
    private static boolean isBizInstalled = true;
    private static boolean isCheck = false;
    private static boolean isFirstIn = false;
    private static ConnectionPool DB_POOL;

    static {
        DB_POOL = ConnectionPool.getInstance();
        String is_check = new BaseBean().getPropValue("weaver_split_table", "is_check");
        if ("0".equals(is_check)){
            start();
        }else {
            checkInstall();
            // 系统启动时，如果分表组件已经安装则初始化组件
            if (isInstalled()) {
                start();
            } else {
                if (isBizInstalled) {
                    init();
                } else {
                    LOGGER.error("分表组件初始化失败：检测到数据库中缺失对应全量表，请按照部署手册[/splittable/doc.jsp]在数据库操作完成后，再启动OA");
                }
            }
        }
    }

    /**
     * 判断分表组件是否已经安装
     * @return true or false
     */
    public static boolean isInstalled() {
        if (!isCheck) {
            checkInstall();
        }
        return isInstalled && isBizInstalled;
    }

    /**
     * 判断分表组件是否已经初始化
     * 判断业务全量表是否已经初始化
     * 通过判断两张分表数据表是否存在来确定
     * @return true or false
     */
    public static void checkInstall() {
        if (!STDBSupport.isSupport(STConfig.DB_TYPE)) {
            return;
        }
        WeaverConnection connection = null;
        try {
            // 判断分表组件本身依赖表是否存在
            connection = DB_POOL.getConnection();
            boolean changeInfoTableIsExist = STDBUtil.checkTableIsExist(STDBConstants.DATA_CHANGE_TABLE_NAME, connection);
            boolean clearInfoTableIsExist = STDBUtil.checkTableIsExist(STDBConstants.DATA_CLEAR_TABLE_NAME, connection);
            // 阈值完善,添加阈值中间表
            boolean thresholdInfoTableIsExist = STDBUtil.checkTableIsExist(STDBConstants.DATA_THRESHOLD_TABLE_NAME, connection);
            isInstalled = changeInfoTableIsExist && clearInfoTableIsExist && thresholdInfoTableIsExist;

            // 检察业务相关全量表是否存在
            for (STBizInitializer bizInitializer: STContext.BIZ_INITIALIZERS()) {
                isBizInstalled = isBizInstalled && bizInitializer.isInitialized();
            }
        } catch (Exception e) {
            LOGGER.error("checkInstall error:", e);
        } finally {
            isCheck = true;
            if (connection != null) {
                DB_POOL.returnConnection(connection);
            }
        }
    }

    private static void start() {
        for (STBizInterceptor bizInterceptor: STContext.BIZ_INTERCEPTORS()) {
            bizInterceptor.init();
        }
        initTasks();
    }

    private static void initTasks() {
        Timer syncTimer = new Timer();
        int syncTime = Integer.valueOf(STConfig.SYNC_TIME) * 1000;
        syncTimer.schedule(new STSyncTask(), syncTime, syncTime);
        //阈值完善。初始化更新阈值的定时任务
        syncTimer.schedule(new STThresholdTask(),5000,60*1000);
        LOGGER.info("STSyncTask is initialized! syncTime:" + syncTime + "ms");
    }

    public static void init() {
        LOGGER.info("======开始初始化分表组件======");
        if (!STDBSupport.isSupport(STConfig.DB_TYPE)) {
            LOGGER.error("不支持的数据库类型:" + STConfig.DB_TYPE);
            return;
        }
        WeaverConnection connection = null;
        try {
            connection = DB_POOL.getConnection();

            // 初始化 数据变动表 和 数据清理表
            LOGGER.info("初始化 数据变动表 和 数据清理表");
            initSplitTables(connection);

            // 初始化 上述表索引
            LOGGER.info("初始化上述表索引");
            initSplitIndexes(connection);

            // 初始化 业务表相关索引和触发器
            for (STBizInitializer bizInitializer: STContext.BIZ_INITIALIZERS()) {
                bizInitializer.init();
            }

            checkInstall();

            if (isInstalled()) {
                start();
            }

        } catch (Exception e) {
            LOGGER.error("初始化分表组件错误:", e);
        } finally {
            DB_POOL.returnConnection(connection);
        }
        LOGGER.info("======分表组件初始化完成======");
    }

    // 创建分表组件相关表
    private static void initSplitTables(WeaverConnection connection) throws Exception {
        WeaverStatement statement = (WeaverStatement) connection.createStatement();
        try {
            boolean changeInfoTableIsExist = STDBUtil.checkTableIsExist(STDBConstants.DATA_CHANGE_TABLE_NAME, connection);
            if (!changeInfoTableIsExist){
                // 创建 数据变动记录 表
                String createDataChangeTableSQL = STContext.CREATE_TABLE().createDataChangeTable();
                statement.originExecuteUpdate(createDataChangeTableSQL);
                if (STDBSupport.ORACLE.equals(STConfig.DB_TYPE)) {
                    STOracleCreateTableUtil oracleCreateTableUtil = (STOracleCreateTableUtil) STContext.CREATE_TABLE();
                    String createOracleSeqSQL = oracleCreateTableUtil.createSequence("ST_DATA_CHANGE_SEQ");
                    statement.originExecuteUpdate(createOracleSeqSQL);
                    String createOracleTiggerSQL = oracleCreateTableUtil.createSequenceTrigger("ST_DATA_CHANGE_ID_TR", "ST_DATA_CHANGE_SEQ", STDBConstants.DATA_CHANGE_TABLE_NAME);
                    statement.originExecuteUpdate(createOracleTiggerSQL);
                }
            }

            boolean clearInfoTableIsExist = STDBUtil.checkTableIsExist(STDBConstants.DATA_CLEAR_TABLE_NAME, connection);
            if (!clearInfoTableIsExist){
                // 创建 数据清理记录 表
                String createDataClearTableSQL = STContext.CREATE_TABLE().createDataClearTable();
                statement.originExecuteUpdate(createDataClearTableSQL);
                if (STDBSupport.ORACLE.equals(STConfig.DB_TYPE)) {
                    STOracleCreateTableUtil oracleCreateTableUtil = (STOracleCreateTableUtil) STContext.CREATE_TABLE();
                    String createOracleSeqSQL = oracleCreateTableUtil.createSequence("ST_DATA_CLEAR_SEQ");
                    statement.originExecuteUpdate(createOracleSeqSQL);
                    //阈值完善 这里第二个参数传错了
                    String createOracleTiggerSQL = oracleCreateTableUtil.createSequenceTrigger("ST_DATA_CLEAR_ID_TR", "ST_DATA_CLEAR_SEQ", STDBConstants.DATA_CLEAR_TABLE_NAME);
                    statement.originExecuteUpdate(createOracleTiggerSQL);
                }
            }

            boolean thresholdInfoTableIsExist = STDBUtil.checkTableIsExist(STDBConstants.DATA_THRESHOLD_TABLE_NAME, connection);
            if (!thresholdInfoTableIsExist){
                // 阈值完善 创建 阈值表
                String createDataThresholdTableSQL = STContext.CREATE_TABLE().createDataThresholdTable();
                statement.originExecuteUpdate(createDataThresholdTableSQL);
                if (STDBSupport.ORACLE.equals(STConfig.DB_TYPE)) {
                    STOracleCreateTableUtil oracleCreateTableUtil = (STOracleCreateTableUtil) STContext.CREATE_TABLE();
                    String createOracleSeqSQL = oracleCreateTableUtil.createSequence("ST_DATA_THRESHOLD_SEQ");
                    statement.originExecuteUpdate(createOracleSeqSQL);
                    String createOracleTiggerSQL = oracleCreateTableUtil.createSequenceTrigger("ST_DATA_THRESHOLD_ID_TR", "ST_DATA_THRESHOLD_SEQ", STDBConstants.DATA_THRESHOLD_TABLE_NAME);
                    statement.originExecuteUpdate(createOracleTiggerSQL);
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            statement.close();
        }
    }

    public static void initSplitIndexes(WeaverConnection connection) throws SQLException {
        WeaverStatement statement = (WeaverStatement) connection.createStatement();

        // 创建 数据变动记录 表索引
        try {
            String createChangeIndexId = STContext.CREATE_INDEX().createChangeIndex_Id();
            statement.originExecuteUpdate(createChangeIndexId);
        } catch (Exception e) {
            LOGGER.error("索引createChangeIndex_Id创建失败：" + e.getMessage());
        }
        try {
            String createChangeIndexDataId = STContext.CREATE_INDEX().createChangeIndex_DataId();
            statement.originExecuteUpdate(createChangeIndexDataId);
        } catch (Exception e) {
            LOGGER.error("索引createChangeIndex_DataId创建失败：" + e.getMessage());
        }
        try {
            String createChangeIndexSynced = STContext.CREATE_INDEX().createChangeIndex_Synced();
            statement.originExecuteUpdate(createChangeIndexSynced);
        } catch (Exception e) {
            LOGGER.error("索引createChangeIndex_Synced创建失败：" + e.getMessage());
        }
        try {
            String createChangeIndexSyncedTableNameEventType = STContext.CREATE_INDEX().createChangeIndex_SyncedTableNameEventType();
            statement.originExecuteUpdate(createChangeIndexSyncedTableNameEventType);
        } catch (Exception e) {
            LOGGER.error("索引createChangeIndex_SyncedTableNameEventType创建失败：" + e.getMessage());
        }
        try {
            String createChangeIndexSyncedSyncTime = STContext.CREATE_INDEX().createChangeIndex_SyncedSyncTime();
            statement.originExecuteUpdate(createChangeIndexSyncedSyncTime);
        } catch (Exception e) {
            LOGGER.error("索引createChangeIndex_SyncedSyncTime创建失败：" + e.getMessage());
        }

        // 创建 数据清理记录 表索引
        try {
            String createClearIndexId = STContext.CREATE_INDEX().createClearIndex_Id();
            statement.originExecuteUpdate(createClearIndexId);
        } catch (Exception e) {
            LOGGER.error("索引createClearIndex_Id创建失败：" + e.getMessage());
        }
        try {
            String createClearIndexDataId = STContext.CREATE_INDEX().createClearIndex_DataId();
            statement.originExecuteUpdate(createClearIndexDataId);
        } catch (Exception e) {
            LOGGER.error("索引createClearIndex_DataId创建失败：" + e.getMessage());
        }
        try {
            String createClearIndexSynced = STContext.CREATE_INDEX().createClearIndex_Synced();
            statement.originExecuteUpdate(createClearIndexSynced);
        } catch (Exception e) {
            LOGGER.error("索引createClearIndex_Synced创建失败：" + e.getMessage());
        }
        try {
            String createClearIndexSyncedTableNameDataId = STContext.CREATE_INDEX().createClearIndex_SyncedTableNameDataId();
            statement.originExecuteUpdate(createClearIndexSyncedTableNameDataId);
        } catch (Exception e) {
            LOGGER.error("索引createClearIndex_SyncedTableNameDataId创建失败：" + e.getMessage());
        }
        try {
            String createClearIndexSyncedSyncTime = STContext.CREATE_INDEX().createClearIndex_SyncedSyncTime();
            statement.originExecuteUpdate(createClearIndexSyncedSyncTime);
        } catch (Exception e) {
            LOGGER.error("索引createClearIndex_SyncedSyncTime创建失败：" + e.getMessage());
        }
        statement.close();
    }



}
